package com.example.myapplication.events;

import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;

import androidx.annotation.Nullable;

import com.example.myapplication.R;
import com.example.myapplication.utils.Utils;

/**
 * Created by ymz0427 on 2021/9/16
 */
public class PhotoView extends View implements IRecycle {

    private final Bitmap bitmap = Utils.loadImage(getResources(), R.drawable.photo, (int) (Utils.getScreenSize(getContext()).x * 0.75));
    private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);

    private final GestureDetector detector = new GestureDetector(getContext(), new GestureDetectorListener());

    private final ScaleGestureDetector scaleDetector = new ScaleGestureDetector(getContext(), new ScaleListener());


    private final static float OVER_FACTOR = 1.5f;
    private float smallScale;
    private float bigScale;
    private float currentScale;
    //将要显示的scale
    private float toScale;

    private float initLeft;
    private float initTop;

    private float offsetX;
    private float offsetY;


    public PhotoView(Context context) {
        super(context);
    }

    public PhotoView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        float ratio = (currentScale - smallScale) / (bigScale - smallScale);
        canvas.translate(offsetX * ratio, offsetY * ratio);

        canvas.scale(currentScale, currentScale, getWidth() / 2f, getHeight() / 2f);
        canvas.drawBitmap(bitmap, initLeft, initTop, paint);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        float scale1 = 1.0f * getHeight() / bitmap.getHeight();
        float scale2 = 1.0f * getWidth() / bitmap.getWidth();

        if (scale1 > scale2) {
            bigScale = scale1;
            smallScale = scale2;
        } else {
            bigScale = scale2;
            smallScale = scale1;
        }
        bigScale = bigScale * OVER_FACTOR;
        currentScale = smallScale;

        initLeft = (getWidth() - bitmap.getWidth()) / 2f;
        initTop = (getHeight() - bitmap.getHeight()) / 2f;
    }

    private void limitOffset() {
        offsetX = limit(offsetX, -(bitmap.getWidth() * bigScale - getWidth()) / 2f,
                (bitmap.getWidth() * bigScale - getWidth()) / 2f);

        offsetY = limit(offsetY, -(bitmap.getHeight() * bigScale - getHeight()) / 2f,
                (bitmap.getHeight() * bigScale - getHeight()) / 2f);
    }

    private float limit(float value, float min, float max) {
        return Math.max(min, Math.min(value, max));
    }


    @Override
    public void recycle() {
        if (!bitmap.isRecycled()) {
            bitmap.recycle();
        }
    }

    private ObjectAnimator objectAnimator;
    private ObjectAnimator getObjectAnimator(float from, float to) {
        if (objectAnimator == null) {
            objectAnimator = ObjectAnimator.ofFloat(this, "currentScale", 0);
        }
        objectAnimator.setFloatValues(from, to);
        return objectAnimator;
    }

    public float getCurrentScale() {
        return currentScale;
    }

    public void setCurrentScale(float currentScale) {
        this.currentScale = currentScale;
        invalidate();
    }

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean result = scaleDetector.onTouchEvent(event);
        if (!scaleDetector.isInProgress()) {
            result = detector.onTouchEvent(event);
        }
        return result;
    }

    private class GestureDetectorListener extends GestureDetector.SimpleOnGestureListener {

        @Override
        public boolean onDoubleTap(MotionEvent e) {
            if (Utils.equals(currentScale, smallScale) || currentScale <= smallScale) {
                toScale = bigScale;

                //以点击坐标点为中心进行放大
                offsetX = (e.getX() - getWidth() / 2f) -
                        (e.getX() - getWidth() / 2f) * bigScale / smallScale;
                offsetY = (e.getY() - getHeight() / 2f) -
                        (e.getY() - getHeight() / 2f) * bigScale / smallScale;

                limitOffset();
            } else {
                toScale = smallScale;
            }
            getObjectAnimator(currentScale, toScale).start();
            currentScale = toScale;

            return super.onDoubleTap(e);
        }

        @Override
        public boolean onDown(MotionEvent e) {
            return true;
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            if (currentScale > smallScale) {
                offsetX -= distanceX;
                offsetY -= distanceY;
                limitOffset();
                invalidate();
            }

            return super.onScroll(e1, e2, distanceX, distanceY);
        }
    }

    private class ScaleListener implements ScaleGestureDetector.OnScaleGestureListener {

        private float initScale;

        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            currentScale = initScale * detector.getScaleFactor();
            currentScale = limit(currentScale, smallScale, bigScale);
            invalidate();
            return false;
        }

        @Override
        public boolean onScaleBegin(ScaleGestureDetector detector) {
            initScale = currentScale;
            return true;
        }

        @Override
        public void onScaleEnd(ScaleGestureDetector detector) {

        }
    }
}
